//
//  Router.m
//  OneStoreFramework
//
//  Created by Aimy on 14-6-23.
//  Copyright (c) 2014年 OneStore. All rights reserved.
//

//#import <BlocksKit/BlocksKit.h>

#import <CoreCode/CoreCode.h>
#import <BaseCode/BaseCode.h>
#import "Router.h"
#import "RouterVO.h"

@interface Router ()

@property (atomic, strong) NSMutableDictionary *routeMapping;
@property (atomic, strong) NSMutableDictionary *nativeCallMapping;

@property (nonatomic, strong) NSString *routeScheme;
@property (nonatomic, strong) NSString *nativeCallScheme;
@property (nonatomic, strong) NSString *appScheme;

@end

@interface Router (Internal)

- (BOOL)p_routeWithRouteVO:(RouterVO *)aVO;

- (void)p_dismissAllPC;

- (BOOL)p_presentModalVC:(UIViewController *)vc params:(NSDictionary *)params;

@end

@implementation Router

- (RouterVO *)getRouterVOWithKey:(NSString *)key {
    if (![self.routeMapping safeObjectForKey:key]) {
        [CoreAlertController alertWithMessage:[NSString stringWithFormat:@"未找到%@对应的RouterVO 请检查%@是否已注册",key,key] andCompleteBlock:nil];
        return nil;
    }
    return [self.routeMapping safeObjectForKey:key];
}

- (NativeCallVO *)getNativeCallVOWithKey:(NSString *)key {
    if (![self.nativeCallMapping safeObjectForKey:key]) {
        [CoreAlertController alertWithMessage:[NSString stringWithFormat:@"未找到%@对应的NativeCallVO 请检查%@是否已注册",key,key] andCompleteBlock:nil];
        return nil;
    }
    return [self.nativeCallMapping safeObjectForKey:key];
}

+ (instancetype)sharedInstance {
    static Router *router = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        router = [Router new];
    });

    return router;
}

- (instancetype)init {
    if (self = [super init]) {
        self.routeMapping = [NSMutableDictionary dictionary];
        self.nativeCallMapping = [NSMutableDictionary dictionary];
        self.routeScheme = @"pb";
        self.nativeCallScheme = @"pbiosfun";
        self.appScheme = @"openapp.pbmobile";
    }

    return self;
}

- (void)updateRouteScheme:(NSString * _Nonnull)routeScheme
         nativeCallScheme:(NSString * _Nonnull)nativeCallScheme
                appScheme:(NSString * _Nonnull)appScheme {
    self.routeScheme = routeScheme ? routeScheme.lowercaseString : @"";
    self.nativeCallScheme = nativeCallScheme ? nativeCallScheme.lowercaseString : @"";
    self.appScheme = appScheme ? appScheme.lowercaseString : @"";
}

- (BaseAppDelegate *)appDelegate {
    return (BaseAppDelegate *) [UIApplication sharedApplication].delegate;
}

- (UITabBarController *)rootTBC {
    UIViewController *rootVC = nil;
    if (@available(iOS 13.0, *)) {
        if ([Predicate multipleScene]) {
            for (UIWindowScene* windowScene in [UIApplication sharedApplication].connectedScenes) {
                if (windowScene.activationState == UISceneActivationStateForegroundActive) {
                   UIWindow *window = windowScene.windows.firstObject;
                    rootVC = window.rootViewController;
                    break;
                }
            }
        } else {
            rootVC = self.appDelegate.window.rootViewController;
        }
    } else {
        rootVC = self.appDelegate.window.rootViewController;
    }
    return [rootVC isKindOfClass:UITabBarController.class] ? (UITabBarController *)rootVC : nil;
}

- (UINavigationController *)currentNC {
    UIViewController *selectedVC = self.rootTBC.selectedViewController;
    if (!selectedVC ) {
        if ([self.appDelegate.window.rootViewController isKindOfClass:UINavigationController.class]) {
            return (UINavigationController *)self.appDelegate.window.rootViewController;
        } else {
            [CoreAlertController alertWithMessage:@"没有设置导航控制器" andCompleteBlock:nil];
            return nil;
        }
    }
    return [selectedVC isKindOfClass:UINavigationController.class] ? (UINavigationController *)selectedVC : nil;
}

- (void)presentPC:(UIViewController *)pc {
    [self p_presentModalVC:pc params:nil];
}

@end

#pragma mark - registery

@implementation Router (registery)

- (void)registerRouterVO:(RouterVO *)aVO withKey:(NSString *)key {
    NSParameterAssert(aVO);
    NSParameterAssert(key);
    key = key.lowercaseString;
    if (aVO && key && !self.routeMapping[key]) {
        aVO.routeKey = key;
        self.routeMapping[key] = aVO;
    }
}

- (void)registerNativeCallVO:(NativeCallVO *)aVO withKey:(NSString *)key {
    NSParameterAssert(aVO);
    NSParameterAssert(key);
    key = key.lowercaseString;
    if (aVO && key && !self.nativeCallMapping[key]) {
        aVO.routeKey = key;
        self.nativeCallMapping[key] = aVO;
    }
}

@end

#pragma mark - route

@implementation Router (route)

#pragma mark route with host

- (BOOL)routeWithKey:(NSString *)key {
    NSParameterAssert(key);
    return [self routeWithKey:key params:nil];
}

- (BOOL)routeWithKey:(NSString *)key params:(NSDictionary *)params {
    NSParameterAssert(key);
    return [self routeWithKey:key params:params callback:nil];
}

- (BOOL)routeWithKey:(NSString *)key params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    NSParameterAssert(key);
    key = key.lowercaseString;
    NSMutableDictionary *mParams = params.mutableCopy ?: @{}.mutableCopy;
    mParams[RouterFromHostKey] = key;
    mParams[RouterFromSchemeKey] = self.routeScheme;
    if (callback) {
        mParams[RouterCallbackKey] = callback;
    }

    RouterVO *vo = [self getRouterVOWithKey:key];
    if (vo){
        vo.params = mParams;
    } else {
        return NO;
    }
    return [self p_routeWithRouteVO:vo];
}

#pragma mark - Router with URL string
- (BOOL)routeWithURLString:(NSString *)aURLString {
    NSParameterAssert(aURLString);
    return [self routeWithURLString:aURLString callback:nil];
}

- (BOOL)routeWithURLString:(NSString *)aURLString callback:(NativeCallVOBlock)callback {
    NSParameterAssert(aURLString);
    return [self routeWithURLString:aURLString params:nil callback:callback];
}

- (BOOL)routeWithURLString:(NSString *)aURLString params:(NSDictionary *)params {
    NSParameterAssert(aURLString);
    return [self routeWithURLString:aURLString params:params callback:nil];
}

- (BOOL)routeWithURLString:(NSString *)aURLString params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    NSParameterAssert(aURLString);
    aURLString = aURLString.lowercaseString;
    NSURL *url = [NSURL URLWithString:aURLString];
    if (!url) {
        url = [NSURL URLWithString:[aURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    }
    return [self routerWithURL:url params:params callback:callback];
}

#pragma mark Router with URL

- (BOOL)routeWithURL:(NSURL *)aURL {
    NSParameterAssert(aURL);
    return [self routeWithURL:aURL callback:nil];
}

- (BOOL)routeWithURL:(NSURL *)aURL callback:(NativeCallVOBlock)callback {
    NSParameterAssert(aURL);
    return [self routerWithURL:aURL params:nil callback:callback];
}

- (BOOL)routerWithURL:(NSURL *)aURL params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    NSParameterAssert(aURL);
    if (!aURL) {
        return NO;
    }
    
    NSURL *yhdSchemeURL = [self getSchemeURLFromRouterURL:aURL];
    NSString *host = yhdSchemeURL.host.lowercaseString;
    NSString *scheme = yhdSchemeURL.scheme.lowercaseString;
    NSString *query = yhdSchemeURL.query.lowercaseString;
    
    NSMutableDictionary *mParams = ((NSDictionary *)([self getBodyParamsFromJsonString:query][RouterParamKey])).mutableCopy ?: @{}.mutableCopy;
    if (params) {
        [mParams addEntriesFromDictionary:params];
    }

    mParams[RouterFromHostKey] = host;
    mParams[RouterFromSchemeKey] = scheme;
    if (callback) {
        mParams[RouterCallbackKey] = callback;
    }

    if ([scheme isEqualToString:self.nativeCallScheme]) {//函数调用
        return [self nativeCallWithKey:host params:mParams callback:callback];
    } else if ([scheme isEqualToString:@"http"]
               || [scheme isEqualToString:@"https"]
               || (host && [scheme isEqualToString:self.routeScheme])) {//页面跳转
        
        RouterVO *routeVO = nil;
        if ([scheme isEqualToString:@"http"]
            || [scheme isEqualToString:@"https"]) {//获取 web 页面对应的 routeVO
            
            routeVO = [self getRouterVOWithKey:@"web"];
            [mParams setObject:aURL.absoluteString forKey:@"url"];
            
        } else if (host && [scheme isEqualToString:self.routeScheme]) {//获取 native 页面对应的 routeVO
            routeVO = [self.routeMapping objectForCaseInsensitiveKey:host];
            
        }
        
        if (!routeVO) { return NO; }
        
        routeVO.params = mParams;
        return [self p_routeWithRouteVO:routeVO];
    } else {
        PBLog(@"Invalid route URL.");
        return NO;
    }
}

- (UIViewController *)viewControllerWithURL:(NSURL *)url params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    NSParameterAssert(url);
    if (!url) {
        return nil;
    }
    
    NSURL *yhdSchemeURL = [self getSchemeURLFromRouterURL:url];
    NSString *host = yhdSchemeURL.host.lowercaseString;
    NSString *scheme = yhdSchemeURL.scheme.lowercaseString;
    NSString *query = yhdSchemeURL.query.lowercaseString;
    
    NSMutableDictionary *mParams = ((NSDictionary *)([self getBodyParamsFromJsonString:query][RouterParamKey])).mutableCopy ?: @{}.mutableCopy;
    if (params) {
        [mParams addEntriesFromDictionary:params];
    }
    
    NSString *key = host;
    if ([scheme isEqualToString:@"http"]
        || [scheme isEqualToString:@"https"]) {
        scheme = self.routeScheme;
        key = @"web";
        mParams[@"url"] = url.absoluteString;
    }
    if ([scheme isEqualToString:self.routeScheme]) {
        return [self viewControllerWithKey:key params:mParams callback:callback];
    }
    return nil;
    
}

- (UIViewController *)viewControllerWithKey:(NSString *)key params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    if (!key) {
        return nil;
    }
    key = key.lowercaseString;
    RouterVO *routeVO = [self.routeMapping objectForCaseInsensitiveKey:key];
    NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
    [parameters addEntriesFromDictionary:params];
    if (callback) {
        [parameters setObject:callback forKey:RouterCallbackKey];
    }
    return [routeVO generateVCWithExtraData:[parameters copy]];
}

- (NSURL *)getSchemeURLFromRouterURL:(NSURL *)url {
    if (![url.scheme.lowercaseString isEqualToString:self.appScheme.lowercaseString]) {
        return url;
    }
    NSRange hostRange = [url.absoluteString safeRangeOfString:url.scheme];
    NSString *urlString = [url.absoluteString stringByReplacingCharactersInRange:hostRange withString:self.routeScheme];
    NSURL *yhdSchemeURL = [NSURL URLWithString:urlString];
    return yhdSchemeURL;
}

@end

#pragma mark - Convenience

@implementation Router (Convenience)

- (void)routeToLogin {
    [self routeWithKey:@"login"];
}

- (void)routeToHomePage {
    [self p_dismissAllPC];
    [self.currentNC popToRootViewControllerAnimated:NO];
    if (self.rootTBC.selectedIndex != 0) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.rootTBC setSelectedIndex:0];
        });
        
    }
}

- (void)routeBack {
    [self.currentNC popViewControllerAnimated:YES];
}

@end

#pragma mark - NativeCall

@implementation Router (NativeCall)

- (id)nativeCallWithKey:(NSString *)key {
    NSParameterAssert(key);
    return [self nativeCallWithKey:key params:nil callback:nil];
}

- (id)nativeCallWithKey:(NSString *)key params:(NSDictionary *)params {
    NSParameterAssert(key);
    return [self nativeCallWithKey:key params:params callback:nil];
}

- (id)nativeCallWithKey:(NSString *)key params:(NSDictionary *)params callback:(NativeCallVOBlock)callback {
    NSParameterAssert(key);
    key = key.lowercaseString;
    NSMutableDictionary *_params = [NSMutableDictionary dictionaryWithDictionary:params];
    if (callback) {
        [_params addEntriesFromDictionary:@{RouterCallbackKey: callback}];
    }
    NativeCallVO *nativeCallVO = [self getNativeCallVOWithKey:key];
    
    if (!nativeCallVO) { return @(0); }
    
    nativeCallVO.params = _params;
    
    if (nativeCallVO.block) {
        return nativeCallVO.block(_params);
    }
    
    return @(0);
}

@end

#pragma mark - Internal

@implementation Router (Internal)

/**
 *  功能:route到RouterVO对应的vc
 */
- (BOOL)p_routeWithRouteVO:(RouterVO *)aVO {
    NSParameterAssert(aVO);
    
    if (aVO.isTab && !aVO.params[@"push"]) {
        return [self p_switchTabAtIndex:aVO.index parameter:aVO.params];
    }
    
    //需要登录(1当前跳转当前页面是否需要登录 2当前是否在登录状态)，则去登录
    if (aVO.needLogin && [self nativeCallWithKey:RouterIsNeedLoginFirstKey]) {
        [self routeWithKey:@"login" params:aVO.params];
        return YES;
    }

    UIViewController *vc = [aVO generateVCWithExtraData:aVO.params];
    if (!vc || [vc isKindOfClass:[UINavigationController class]]) {
        return NO;
    }

    //Present PC情况处理
    if ([vc isPc]) {
        return [self p_presentModalVC:vc params:aVO.params];
    }

    //隐藏PC
    [self p_dismissAllPC];

    if ([aVO.params.allKeys containsObject:@"isAnimated"]) {
        id animatedValue = aVO.params[@"isAnimated"];
        if ([animatedValue isKindOfClass:NSString.class]) {
            NSString *animatedString = [(NSString *)animatedValue lowercaseString];
            aVO.animated = [@[@"yes", @"true", @"1"] containsObject:animatedString];
        } else if ([animatedValue isKindOfClass:NSNumber.class]){
            aVO.animated = [(NSNumber *)animatedValue boolValue];
        }
    }
    
    RouterWillExecuteBlock routerWillExeBlock = aVO.params[RouterWillExecuteKey];
    if(routerWillExeBlock) {
        routerWillExeBlock(vc);
    }
    
    [self.currentNC pushViewController:vc animated:aVO.isAnimated];
    return YES;
}

- (BOOL)p_presentModalVC:(UIViewController *)vc params:(NSDictionary *)params {
    //Present PC情况处理
    if ([vc isPc]) {
        if ([[self.appDelegate.modalWindow.rootViewController.childViewControllers lastObject] isKindOfClass:[vc class]] && !vc.isPresented) {
            return YES;
        } else {
            if (![vc shouldShareScreen]) {
                [self p_dismissAllPC];
            }
            [vc addToRootVC];
            
            // hard code：之所以延迟0.1秒，是因为需要上面p_dismissAllPC执行完毕之后再present
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) {
                RouterWillExecuteBlock routerWillExeBlock = params[RouterWillExecuteKey];
                if(routerWillExeBlock) {
                    routerWillExeBlock(vc);
                }
                [vc presentViewControllerAnimated:YES completion:^{}];
            });
            return YES;
        }
    }
    return NO;
}

- (BOOL)p_switchTabAtIndex:(NSUInteger)index parameter:(NSDictionary *)parameter {
    [self p_dismissAllPC];
    [self.currentNC popToRootViewControllerAnimated:NO];
    
    if (self.rootTBC.selectedIndex != index) {
        self.rootTBC.selectedIndex = index;
    }
    
    return YES;
}

/**
 *  功能:关闭所有pc
 */
- (void)p_dismissAllPC {
    if ([self.appDelegate isKindOfClass:[BaseAppDelegate class]] && self.appDelegate.modalWindow){
        for (UIViewController *childVC in self.appDelegate.modalWindow.rootViewController.childViewControllers) {
            if ([childVC isPc]) {
                [childVC dismissViewControllerAnimated:NO completion:nil];
            }
        }
    }
}

@end

@implementation Router (URL)

- (NSString *)urlStringForRouteKey:(NSString *)key andParams:(NSDictionary *)params {
    NSParameterAssert(key);
    key = key.lowercaseString;
    NSString *urlString = [NSString stringWithFormat:@"%@://%@", self.routeScheme, key];

    NSString *json = [CoreJSONUtil stringFromDict:params];
    if (!json) {
        return urlString;
    }

    NSString *jsonString = [urlString stringByAppendingFormat:@"?%@=%@", RouterParamKey, json];
    jsonString = [jsonString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    return jsonString;
}

- (NSDictionary *)getBodyParamsFromJsonString:(NSString *)aJsonString {
    //urldecode
    NSString *jsonString = [aJsonString stringByRemovingPercentEncoding];

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    if (!jsonString) {
        return dict;
    }
    NSRange range = [jsonString rangeOfString:@"=" options:NSCaseInsensitiveSearch];
    if (range.location == NSNotFound) {
        return dict;
    }
    
    NSString *keyString = [jsonString substringWithRange:NSMakeRange(0, range.location)];
    NSString *valueString = [jsonString substringFromIndex:range.location+range.length];
    
    if ([RouterParamKey isEqualToString:keyString] || [RouterAppParamKey isEqualToString:keyString]) {
        if (valueString) {
            NSRange endCharRange = [jsonString rangeOfString:@"}" options:NSBackwardsSearch];
            if (endCharRange.location != NSNotFound) {
                jsonString = [jsonString substringToIndex:endCharRange.location + 1];
            }
            NSRange range = [jsonString rangeOfString:@"="];
            //除去body＝剩下纯json格式string
            NSString *jsonStr = [jsonString substringFromIndex:range.location + 1];

            if ([[jsonStr safeSubstringFromIndex:(jsonStr.length - 1)] isEqualToString:@"\""]) { // 去掉末尾"号
                jsonStr = [jsonStr substringToIndex:(jsonStr.length - 1)];
            }
            dict[RouterParamKey] = [CoreJSONUtil dictFromString:jsonStr];
        }
    }

    [dict.copy enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        if ([obj isKindOfClass:[NSNumber class]]) {
            dict[key] = [obj stringValue];
        }
    }];

    if (!dict[RouterParamKey] || [dict[RouterParamKey] isEqual:[NSNull null]]) {
        dict[RouterParamKey] = @{};
    }
    return dict;
}


@end
